package com.yy.micro.magic.core.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.yy.micro.magic.core.context.MagicCubeContext;
import com.yy.micro.magic.core.model.PlanSchedule;
import com.yy.micro.magic.core.result.name.NameStrategy;
import com.yy.micro.magic.core.model.RuleDescriptor;
import com.yy.micro.magic.core.result.value.ValueStrategy;
import com.yy.micro.magic.utils.MapUtils;

import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.Map;

import javax.validation.constraints.NotNull;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

@ApiModel(description = "MagicRequest,魔方的输入参数，指定planCode和待处理数据源")
public class MagicRequest {
    /**
     * 映射模板code,对应模板中resourceCode属性
     */
    @ApiModelProperty(name = "planCode",notes = "Magic planCode，转换plan的code标识",required = true,position = 0)
    private String planCode;

    /**
     * 选择处理器,在Map框架 中,可以定义多个处理器,指定处理器名
     */
    @ApiModelProperty(name = "processor",notes = "选择处理器,在Magic框架中,可以定义多个处理器,指定处理器名",example = "strategy",dataType = "String")
    private String processor = "strategy";

    /**
     * 请求中源数据
     *
     */
    @ApiModelProperty(name = "sourceData",notes = "输入的源数据",required = true,dataType = "Map<String,Object>",position = 1)
    private Map<String, Object> sourceData;
    /**
     * 经过变换后,转换为一层Map结构的请求数据
     */
    @ApiModelProperty(name = "runtimeData",hidden = true)
    @JsonIgnore
    private Map<String, Object> runtimeData;
    /**
     * 附加数据
     */
    @ApiModelProperty(name = "additionalData",notes = "输入参数中的附加数据，做为原数据的补充。",dataType = "Map<String,Object>")
    private Map<String, Object> additionalData;

    /**
     * 映射上下文,用于存储映射所需要的资源,如映射 模板,及其他 一些定义,资源加载在Loader中实现
     */
    @ApiModelProperty(name ="" ,hidden = true)
    private MagicCubeContext context;

    @ApiModelProperty(name = "schedule",notes = "plan schedule",hidden = true)
    private PlanSchedule schedule;

    /**
     * 在输出 中是否包含请求内容,默认不包含
     */
    @ApiModelProperty(name = "includeSourceData",notes = "在输出中是否包含请求内容,默认不包含",dataType = "Boolean")
    private boolean includeSourceData = false;

    @ApiModelProperty(name = "nameStrategy",notes = "结果中key的命名策略",example ="NameStrategy.NoneNameStrategy.instance" )
    private NameStrategy nameStrategy = NameStrategy.NoneNameStrategy.instance;

    /**
     * value过滤，把不符合条件的value从结果中移除，匹配方式按位与的方式
     */
    @ApiModelProperty(name = "valueStrategies",notes = "value过滤策略，把不符合条件的value从结果中移除",dataType = "int",example = "ValueStrategy.TRUE_VALUE_STRATEGY|ValueStrategy.CLEAN_TEMP_VALUE_STRATEGY")
    private int valueStrategies = ValueStrategy.TRUE_VALUE_STRATEGY|ValueStrategy.CLEAN_TEMP_VALUE_STRATEGY;


    public String getPlanCode() {
        return planCode;
    }

    public MagicRequest setPlanCode(final String planCode) {
        Assert.hasText(planCode,"planCode must not empty!");
        this.planCode = planCode;
        return this;
    }

    public String getProcessor() {
        return processor;
    }

    public MagicRequest setProcessor(final String processor) {
        if (!StringUtils.isEmpty(processor)){
            this.processor = processor;
        }
        return this;
    }

    public Map<String, Object> getSourceData() {
        return sourceData;
    }

    public MagicRequest setSourceData(final Map<String, Object> sourceData) {
        this.sourceData = sourceData;
        return this;
    }

    public Map<String, Object> getRuntimeData() {
        if (null == runtimeData){
            if (null != sourceData){
                runtimeData = MapUtils.mapToLevel(sourceData);
            }else {
                runtimeData = Collections.EMPTY_MAP;
            }
        }
        return runtimeData;
    }

    public MagicRequest setRuntimeData(final Map<String, Object> runtimeData) {
        this.runtimeData = runtimeData;
        return this;
    }

    public Map<String, Object> getAdditionalData() {
        return additionalData;
    }

    public MagicRequest setAdditionalData(final Map<String, Object> additionalData) {
        this.additionalData = additionalData;
        return this;
    }

    public MagicCubeContext getContext() {
        return context;
    }

    public MagicRequest setContext(final MagicCubeContext context) {
        this.context = context;
        return this;
    }

    public void setSchedule(@NotNull PlanSchedule schedule) {
        this.schedule = schedule;
    }

    public PlanSchedule getSchedule() {
        return schedule;
    }

    public boolean isIncludeSourceData() {
        return includeSourceData;
    }

    public MagicRequest setIncludeSourceData(final boolean includeSourceData) {
        this.includeSourceData = includeSourceData;
        return this;
    }

    public void setValueStrategies(final int valueStrategies) {
        this.valueStrategies = valueStrategies;
    }

    public void addValueStrategy(int valueStrategy){
        this.valueStrategies |=valueStrategy;
    }

    public int getValueStrategies() {
        return valueStrategies;
    }

    public void setNameStrategy(final NameStrategy nameStrategy) {
        this.nameStrategy = nameStrategy;
    }

    public NameStrategy getNameStrategy() {
        return nameStrategy;
    }

    @JsonIgnore
    public static MagicRequest create(String planCode){
        MagicRequest request = new MagicRequest();
        request.setPlanCode(planCode);
        return request;
    }

}
